package cn.kailangtu.serialutils.api;

import android.os.SystemClock;
import android.provider.Settings;
import android.util.Log;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.concurrent.LinkedBlockingQueue;
import android_serialport_api.SerialPort;
import cn.kailangtu.commontools.CommonUtils;
import cn.kailangtu.commontools.Loggers;
import cn.kailangtu.serialutils.modbus.ModbusRtuValidator;

public class SerialPortApi485 {

    private static String TAG = "SerialPortApi==>";
    private String portName;
    private int baudrate;
    private int flags;
    private LinkedBlockingQueue<String> reportMsgQueue = null;
    private LinkedBlockingQueue<String> sendMsgQueue = null;

    private  OutputStream os;
    private  InputStream is;
    private  SerialPort serial;
    private  int resultSize;
    private  byte[] rxByteArray;
    private ReceiveMsgListenerV2 listener;
    private  boolean isReading = false;

    private ComBase comBase;


    public SerialPortApi485(ComBase comBase){
        reportMsgQueue = new LinkedBlockingQueue<>(500);
        sendMsgQueue = new LinkedBlockingQueue<>(500);
        this.comBase = comBase;
        spy();
    }


    /***
     * 打开串口
     * @param portName 串口名称，例：/dev/ttyS1
     * @param baudrate 波特率
     * @param flags flag
     * @return
     */
    public boolean openSerialPort(String portName,int baudrate,int flags)
    {

        try {
            lastReceiveTime = System.currentTimeMillis();
            this.portName = portName;
            this.baudrate = baudrate;
            this.flags = flags;


            Log.d("openSerialPort","PORTNAME:"+portName+" ||| BAUDRATE:"+baudrate + " ||| "+flags);


            serial = new SerialPort(new File(portName), baudrate, flags);
            os = serial.getOutputStream();
            is = serial.getInputStream();


           // SendThread sendThread =new SendThread();
           // sendThread.start();

//            ProcessThread processThread = new ProcessThread();
//            processThread.start();

            ReadThread();
            Log.d("openSerialPort","打开成功");
            return true;
        }
        catch(Exception e)
        {
            e.printStackTrace();
        }
        return false;
    }

    public void close(){
        serial.close();

    }
//发数据
    private void sendBytes(byte[] data){
        try {
          //  Log.d("SerialPortApi485","SEND:"+CommonUtils.ByteArrayToHexString(data));
            Loggers.serialPortApiInfo("SEND:"+CommonUtils.ByteArrayToHexString(data));
            lastSendTime = System.currentTimeMillis();
            if(lastSendTime - lastReceiveTime > 500)
            {
                resultSize = 0;
                rxByteArray = null;
            }
            os.write(data);
            os.flush();
        } catch (IOException e) {
            e.printStackTrace();
        } catch(Exception e)
        {
            e.printStackTrace();
        }
    }

   long lastSendTime2 = 0;
    long lastReveiveTime2 = 0;
    public synchronized   void sendAndReceive(byte[] data)
    {
        try {
            rxByteArray = null;
            resultSize = 0;
            String sendString = CommonUtils.ByteArrayToHexString(data);
            Log.d("SEND AND RECEIVE","SEND:"+sendString);
            if(data[1] == 6)
            {

                Log.d("0106指令","发："+CommonUtils.ByteArrayToHexString(data)+" "
                        +"距上次发:"+(System.currentTimeMillis() - lastSendTime2)+" "
                        +"距上次收:"+(System.currentTimeMillis() - lastReveiveTime2));
            }
            lastSendTime2 = System.currentTimeMillis();
            os.write(data);
            os.flush();
            int i =0;
            int timeOut = 100;
            while(i < timeOut)
            {

                SystemClock.sleep(5);
                if(isCompleteModbus()){
                    i = timeOut;
                }
                i++;
            }

            /*
            if(rxByteArray != null)
            {
                Log.d("SEND AND RECEIVE","RECEIVE,长度:"+rxByteArray.length);
                Log.d("SEND AND RECEIVE","RECEIVE:"+CommonUtils.ByteArrayToHexString(rxByteArray));
            }
            else{
                Log.d("SEND AND RECEIVE","RECEIVE:空");
            }

             */
            lastReveiveTime2 = System.currentTimeMillis();
            if(rxByteArray != null && sendString.equals("0103119400500126"))
            {
                Log.d("SHOOTLEE_PLC","收到的为："+CommonUtils.ByteArrayToHexString(rxByteArray));
            }
            rxByteArray = null;
            resultSize = 0;


        } catch (IOException e) {
            e.printStackTrace();
            Log.d("SEND AND RECEIVE","RECEIVE，ERR:"+e.getMessage());
        } catch(Exception e)
        {
            e.printStackTrace();
            Log.d("SEND AND RECEIVE","RECEIVE，ERR:"+e.getMessage());
        }
    }




    private  boolean onDataReceived(byte[] paramArrayOfByte,
                                       int paramInt) throws ModbusError {

        lastReceiveTime = System.currentTimeMillis();
        rxByteArray = CommonUtils.ArrayAppend(rxByteArray, paramArrayOfByte, paramInt);
        if (rxByteArray == null) {
            return false;
        }
        resultSize += paramInt;




        if(this.listener != null)
        {
            this.listener.onReceiveData(rxByteArray.clone());
            rxByteArray = null;
            resultSize = 0;
        }




        /*
        if(isCompleteModbus())
        {
            resultSize = 0;
            rxByteArray = null;
            return true;
        }
        else if(rxByteArray.length>10000)
        {
            resultSize = 0;
            rxByteArray = null;
        }

         */
        return false;
    }

    boolean isOpenReadThread = false;
    public void ReadThread()
    {
        if(!isOpenReadThread) {
            isOpenReadThread = true;
            new Thread(new Runnable() {
                @Override
                public void run() {
                    while(isOpenReadThread)
                    {
                        try {
                            byte[] buffer = new byte[64];
                            if (is == null) {
                                return;
                            }
                            SystemClock.sleep(1);
                            int tempSize;
                            tempSize = is.read(buffer);
                            if (tempSize > 0) {
                                onDataReceived(buffer, tempSize);
                            }
                        } catch (IOException e) {
                            //Log.e(TAG, "ReadThread3异常");
                            e.printStackTrace();
                            return;
                        } catch (ModbusError e) {
                            throw new RuntimeException(e);
                        }
                    }
                    isOpenReadThread = false;
                }
            }).start();
        }
    }


    private  boolean onDataReceivedEx(byte[] paramArrayOfByte,
                                    int paramInt) throws ModbusError {
        rxByteArray = CommonUtils.ArrayAppend(rxByteArray, paramArrayOfByte, paramInt);
        if (rxByteArray == null) {
            return false;
        }
        resultSize += paramInt;
        if(isCompleteModbus())
        {
            return true;
        }
        return false;
    }



    boolean isSending = false;
    boolean isProcess = false;

    private class SendThread extends Thread{
        @Override
        public void run(){
            super.run();
            if(!isSending){
                isSending = true;
                while(true){
                    try {
                        String currentCmd = sendMsgQueue.take();
                        Log.d("SerialPortApi485","SEND:"+currentCmd);
                        sendBytes(CommonUtils.hexStringToByteArray(currentCmd));
                        int i =0;
                        while(i < 40)
                        {
                            byte[] buffer = new byte[255];
                            if (is == null) {
                                return;
                            }
                            SystemClock.sleep(5);
                            int tempSize;
                            tempSize = is.read(buffer);
                            if (tempSize > 0) {
                                if(onDataReceived(buffer, tempSize))
                                {
                                    i = 40;
                                }
                            }
                            i++;
                        }
                        rxByteArray = null;
                        resultSize = 0;
                    } catch (Exception e) {
                        e.printStackTrace();
                    }
                }
                //isSending = false;
            }
        }
    }



    private boolean isCompleteModbus(){
        if(rxByteArray != null) {
            Log.d("SEND AND RECEIVE","CHECK:"+CommonUtils.ByteArrayToHexString(rxByteArray));
            boolean check =  ModbusRtuValidator.isCompleteModbusFrame(rxByteArray);
            if(check)
            {
                if(this.comBase != null)
                {

                    this.comBase.receiveData(rxByteArray);
                }
                return true;
            }
            else
            {
                if(rxByteArray.length> 3)
                {
                    if(rxByteArray[1] == 3)
                    {
                        int length =  (rxByteArray[2] & 0xFF);
                        if(rxByteArray.length >= (length+5))
                        {
                            Log.d("SHOOTLEE_PLC","确发了长度确认:"+length+ " || "+rxByteArray.length);
                            this.comBase.receiveData(rxByteArray);
                            return true;
                        }
                    }
                }
            }
        }
        return false;
    }




    public void addSendString(String sendString)
    {
        sendMsgQueue.offer(sendString);
    }


    private void reopen()
    {
        try{
            Log.d("SHOOTLEE_REOPEN","1");
            isOpenReadThread = false;
            Log.d("SHOOTLEE_REOPEN","2");
            os.close();
            Log.d("SHOOTLEE_REOPEN","3");
            is.close();
            Log.d("SHOOTLEE_REOPEN","4");
            serial.close();
            Log.d("SHOOTLEE_REOPEN","5");
            SystemClock.sleep(2000);
        }
        catch(Exception e)
        {
            Log.d("SHOOTLEE_REOPEN","ERR:"+e.getMessage());
        }
        openSerialPort(this.portName,this.baudrate,this.flags);
    }

    long lastReceiveTime = System.currentTimeMillis();
    long lastSendTime = 0;
    public void spy(){

        new Thread(new Runnable() {
            @Override
            public void run() {
                while(true){
                    if(System.currentTimeMillis() - lastReceiveTime > 5000)
                    {
                        lastReceiveTime = System.currentTimeMillis();
                        reopen();
                    }


                    SystemClock.sleep(1000);
                }
            }
        }).start();
    }



    public void setListener(ReceiveMsgListenerV2 listener) {
        this.listener = listener;
    }
}
